#include "wx/wxprec.h"
#if wxUSE_PRINTING_ARCHITECTURE && wxUSE_POSTSCRIPT && (!defined(__WXMSW__) || wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW)
//#error mmmmmmm
#ifndef WX_PRECOMP
#include "wx/utils.h"
#include "wx/dc.h"
#include "wx/app.h"
#include "wx/msgdlg.h"
#include "wx/intl.h"
#include "wx/progdlg.h"
#include "wx/log.h"
#include "wx/dcprint.h"
#endif

#include "wx/generic/printps.h"
#include "wx/printdlg.h"
#include "wx/generic/prntdlgg.h"
#include "wx/generic/progdlgg.h"
#include "wx/paper.h"

#include <stdlib.h>

IMPLEMENT_DYNAMIC_CLASS( wxPostScriptPrinter, wxPrinterBase )
IMPLEMENT_CLASS( wxPostScriptPrintPreview, wxPrintPreviewBase )

wxPostScriptPrinter::wxPostScriptPrinter( wxPrintDialogData *data )
  : wxPrinterBase( data ) {
}

wxPostScriptPrinter::~wxPostScriptPrinter() {
}

bool wxPostScriptPrinter::Print( wxWindow *parent, wxPrintout *printout, bool prompt ) {
  sm_abortIt = false;
  sm_abortWindow = ( wxWindow * ) NULL;
  if( !printout ) {
    sm_lastError = wxPRINTER_ERROR;
    return false;
  }
  printout->SetIsPreview( false );
  if( m_printDialogData.GetMinPage() < 1 ) {
    m_printDialogData.SetMinPage( 1 );
  }
  if( m_printDialogData.GetMaxPage() < 1 ) {
    m_printDialogData.SetMaxPage( 9999 );
  }
  wxDC *dc;
  if( prompt ) {
    dc = PrintDialog( parent );
    if( !dc ) {
      return false;
    }
  } else {
    dc = new wxPostScriptDC( GetPrintDialogData().GetPrintData() );
  }
  if( !dc || !dc->Ok() ) {
    if( dc ) {
      delete dc;
    }
    sm_lastError = wxPRINTER_ERROR;
    return false;
  }
  wxSize ScreenPixels = wxGetDisplaySize();
  wxSize ScreenMM = wxGetDisplaySizeMM();
  printout->SetPPIScreen( ( int )( ( ScreenPixels.GetWidth() * 25.4 ) / ScreenMM.GetWidth() ),
                          ( int )( ( ScreenPixels.GetHeight() * 25.4 ) / ScreenMM.GetHeight() ) );
  printout->SetPPIPrinter( wxPostScriptDC::GetResolution(),
                           wxPostScriptDC::GetResolution() );
  printout->SetDC( dc );
  int w, h;
  dc->GetSize( &w, &h );
  printout->SetPageSizePixels( ( int )w, ( int )h );
  printout->SetPaperRectPixels( wxRect( 0, 0, w, h ) );
  int mw, mh;
  dc->GetSizeMM( &mw, &mh );
  printout->SetPageSizeMM( ( int )mw, ( int )mh );
  // Create an abort window
  wxBeginBusyCursor();
  printout->OnPreparePrinting();
  // Get some parameters from the printout, if defined
  int fromPage, toPage;
  int minPage, maxPage;
  printout->GetPageInfo( &minPage, &maxPage, &fromPage, &toPage );
  if( maxPage == 0 ) {
    sm_lastError = wxPRINTER_ERROR;
    wxEndBusyCursor();
    return false;
  }
  // Only set min and max, because from and to have been
  // set by the user
  m_printDialogData.SetMinPage( minPage );
  m_printDialogData.SetMaxPage( maxPage );
  if( m_printDialogData.GetFromPage() < minPage ) {
    m_printDialogData.SetFromPage( minPage );
  }
  if( m_printDialogData.GetToPage() > maxPage ) {
    m_printDialogData.SetToPage( maxPage );
  }
  int
  pagesPerCopy = m_printDialogData.GetToPage() - m_printDialogData.GetFromPage() + 1,
  totalPages = pagesPerCopy * m_printDialogData.GetNoCopies(),
  printedPages = 0;
  // Open the progress bar dialog
  wxProgressDialog *progressDialog = new wxProgressDialog(
    printout->GetTitle(),
    _( "Printing..." ),
    totalPages,
    parent,
    wxPD_CAN_ABORT | wxPD_AUTO_HIDE | wxPD_APP_MODAL );
  printout->OnBeginPrinting();
  sm_lastError = wxPRINTER_NO_ERROR;
  bool keepGoing = true;
  int copyCount;
  for( copyCount = 1; copyCount <= m_printDialogData.GetNoCopies(); copyCount ++ ) {
    if( !printout->OnBeginDocument( m_printDialogData.GetFromPage(), m_printDialogData.GetToPage() ) ) {
      wxEndBusyCursor();
      wxLogError( _( "Could not start printing." ) );
      sm_lastError = wxPRINTER_ERROR;
      break;
    }
    if( sm_abortIt ) {
      sm_lastError = wxPRINTER_CANCELLED;
      break;
    }
    int pn;
    for( pn = m_printDialogData.GetFromPage(); keepGoing && ( pn <= m_printDialogData.GetToPage() ) && printout->HasPage( pn );
         pn++ ) {
      if( sm_abortIt ) {
        keepGoing = false;
        sm_lastError = wxPRINTER_CANCELLED;
        break;
      } else {
        wxString msg;
        msg.Printf( _( "Printing page %d..." ), printedPages + 1 );
        if( progressDialog->Update( printedPages++, msg ) ) {
          dc->StartPage();
          printout->OnPrintPage( pn );
          dc->EndPage();
        } else {
          sm_abortIt = true;
          sm_lastError = wxPRINTER_CANCELLED;
          keepGoing = false;
        }
      }
      wxYield();
    }
    printout->OnEndDocument();
  }
  printout->OnEndPrinting();
  delete progressDialog;
  wxEndBusyCursor();
  delete dc;
  return ( sm_lastError == wxPRINTER_NO_ERROR );
}

wxDC* wxPostScriptPrinter::PrintDialog( wxWindow *parent ) {
  wxDC* dc = ( wxDC* ) NULL;
  wxGenericPrintDialog dialog( parent, &m_printDialogData );
  if( dialog.ShowModal() == wxID_OK ) {
    dc = dialog.GetPrintDC();
    m_printDialogData = dialog.GetPrintDialogData();
    if( dc == NULL ) {
      sm_lastError = wxPRINTER_ERROR;
    } else
    { sm_lastError = wxPRINTER_NO_ERROR; }
  } else
  { sm_lastError = wxPRINTER_CANCELLED; }
  return dc;
}

bool wxPostScriptPrinter::Setup( wxWindow *( parent ) ) {
  return false;
}

void wxPostScriptPrintPreview::Init( wxPrintout * ( printout ),
                                     wxPrintout * ( printoutForPrinting ) ) {
  DetermineScaling();
}

wxPostScriptPrintPreview::wxPostScriptPrintPreview( wxPrintout *printout,
    wxPrintout *printoutForPrinting,
    wxPrintDialogData *data )
  : wxPrintPreviewBase( printout, printoutForPrinting, data ) {
  Init( printout, printoutForPrinting );
}

wxPostScriptPrintPreview::wxPostScriptPrintPreview( wxPrintout *printout,
    wxPrintout *printoutForPrinting,
    wxPrintData *data )
  : wxPrintPreviewBase( printout, printoutForPrinting, data ) {
  Init( printout, printoutForPrinting );
}

wxPostScriptPrintPreview::~wxPostScriptPrintPreview() {
}

bool wxPostScriptPrintPreview::Print( bool interactive ) {
  if( !m_printPrintout ) {
    return false;
  }
  wxPrinter printer( & m_printDialogData );
  return printer.Print( m_previewFrame, m_printPrintout, interactive );
}

void wxPostScriptPrintPreview::DetermineScaling() {
  wxPaperSize paperType = m_printDialogData.GetPrintData().GetPaperId();
  if( paperType == wxPAPER_NONE ) {
    paperType = wxPAPER_NONE;
  }
  wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType( paperType );
  if( !paper ) {
    paper = wxThePrintPaperDatabase->FindPaperType( wxPAPER_A4 );
  }
  if( paper ) {
    wxSize ScreenPixels = wxGetDisplaySize();
    wxSize ScreenMM = wxGetDisplaySizeMM();
    m_previewPrintout->SetPPIScreen( ( int )( ( ScreenPixels.GetWidth() * 25.4 ) / ScreenMM.GetWidth() ),
                                     ( int )( ( ScreenPixels.GetHeight() * 25.4 ) / ScreenMM.GetHeight() ) );
    m_previewPrintout->SetPPIPrinter( wxPostScriptDC::GetResolution(), wxPostScriptDC::GetResolution() );
    wxSize sizeDevUnits( paper->GetSizeDeviceUnits() );
    sizeDevUnits.x = ( wxCoord )( ( float )sizeDevUnits.x * wxPostScriptDC::GetResolution() / 72.0 );
    sizeDevUnits.y = ( wxCoord )( ( float )sizeDevUnits.y * wxPostScriptDC::GetResolution() / 72.0 );
    wxSize sizeTenthsMM( paper->GetSize() );
    wxSize sizeMM( sizeTenthsMM.x / 10, sizeTenthsMM.y / 10 );
    // If in landscape mode, we need to swap the width and height.
    if( m_printDialogData.GetPrintData().GetOrientation() == wxLANDSCAPE ) {
      m_pageWidth = sizeDevUnits.y;
      m_pageHeight = sizeDevUnits.x;
      m_previewPrintout->SetPageSizeMM( sizeMM.y, sizeMM.x );
    } else {
      m_pageWidth = sizeDevUnits.x;
      m_pageHeight = sizeDevUnits.y;
      m_previewPrintout->SetPageSizeMM( sizeMM.x, sizeMM.y );
    }
    m_previewPrintout->SetPageSizePixels( m_pageWidth, m_pageHeight );
    m_previewPrintout->SetPaperRectPixels( wxRect( 0, 0, m_pageWidth, m_pageHeight ) );
    // At 100%, the page should look about page-size on the screen.
    m_previewScaleX = ( float )0.8 * 72.0 / ( float )wxPostScriptDC::GetResolution();
    m_previewScaleY = m_previewScaleX;
  }
}

#endif
